package net.villonanny.strategy;

import net.villonanny.ConversationException;
import net.villonanny.TimeWhenRunnable;
import net.villonanny.Translator;
import net.villonanny.Util;
import net.villonanny.entity.Village;
import net.villonanny.type.ResourceTypeMap;

import org.apache.commons.configuration.SubnodeConfiguration;
import org.apache.log4j.Logger;

abstract public class Strategy {
	private final static Logger log = Logger.getLogger(Strategy.class);
	protected Village village;
	protected Util util;
	protected Translator translator;
	protected TimeWhenRunnable timeWhenRunnable;
	protected SubnodeConfiguration config;
	protected String id; // Uniquely identifies the instance (could be created from config but keeping a copy is safer here)
	protected boolean deleted = true; // Deleted unless init() is called
	private String desc;
	private int index;
	
	/**
	 * Executes the strategy 
	 * @return the time when it should be run again
	 * @throws ConversationException
	 */
	abstract public TimeWhenRunnable execute() throws ConversationException;
	
	/**
	 * 
	 * @param strategyConfig the part of the configuration that pertains to this strategy
	 * @param village
	 */
	public void init(SubnodeConfiguration strategyConfig, Village village) {
		this.config = strategyConfig;
		this.village = village;
		this.util = village.getUtil();
		this.translator = village.getTranslator();
		this.id = createId(strategyConfig);
		this.deleted = false;
		
		
		//set description
		String className = config.getString("/@class");
		this.desc = config.getString("/@desc", className); // desc is optional

	}
	
	public String getId() {
		return id;
	}

	public TimeWhenRunnable getTimeWhenRunnable() {
		return timeWhenRunnable;
	}

	public void setTimeWhenRunnable(TimeWhenRunnable timeWhenRunnable) {
		this.timeWhenRunnable = timeWhenRunnable;
	}

	public String getDesc() {
//		String className = config.getString("/@class");
//		String desc = config.getString("/@desc", className); // desc is optional
		return this.desc + " (" + index + ")";
	}
	
	public void setIndex(int index) {
		this.index = index;
	}
	
	public void setDesc(String desc) {
		this.desc = desc;
	}

	/**
	 * Return the minimum resources needed to run regardless of time, or null if not applicable
	 * @return
	 */
	public ResourceTypeMap getTriggeringResources() {
		return null;
	}
	
	/**
	 * Return true if this strategy modifies village resources
	 * @return
	 */
	public boolean modifiesResources() {
		return false;
	}
	
	public void updateConfig(SubnodeConfiguration strategyConfig, Util util) {
		this.util = util;
		this.config = strategyConfig;
		this.id = createId(strategyConfig);
		this.timeWhenRunnable = TimeWhenRunnable.NOW;
		this.deleted = false;
		log.debug("Updating strategy config for " + getDesc());
	}
	
	/**
	 * Returns a string that uniquely represents the strategy instance
	 * with values taken from the configuration. Should be refined by subclasses when needed. 
	 * @param strategyConfig
	 * @return the string ID
	 */
	 public String createId(SubnodeConfiguration strategyConfig) {
		 // The basic form of ID is made of class + desc
		 String className = strategyConfig.getString("/@class");
		 String desc = strategyConfig.getString("/@desc");
		 // Enabled not used because a strategy should not change identity when disabled
		 // String enabled = strategyConfig.getString("/@enabled");
		 return new StringBuffer(className).append("#").append(desc).toString();
	 }

	public boolean isDeleted() {
		return deleted;
	}

	public void setDeleted(boolean deleted) {
		this.deleted = deleted;
	}

// TODO questo andrebbe bene se si usasse una percentuale, del tipo "se le risorse sono aumentate del 40%".
// TODO altrimenti non va bene perche' le risorse aumentano sempre comunque!
//	// Return true if the strategy should be called when a resource has been increased since last run
//	public boolean isCallableOnResourceIncrease() {
//		return false;
//	}
	
}
